/**************************************************************************//**
 * @item     CosyOS-II Config
 * @file     mcucfg_cmx.h
 * @brief    CMSIS Cortex-M Core Config File
 * @author   迟凯峰
 * @version  V1.0.1
 * @date     2023.10.25
 ******************************************************************************/

#ifndef __MCUCFG_CMX_H
#define __MCUCFG_CMX_H

/******************************************************************************
 *                             USER Definitions                               *
 ******************************************************************************/

          //*** <<< Use Configuration Wizard in Context Menu >>> ***//

///////////////////////////////////////////////////////////////////////////////
// <o> 系统滴答时钟源
// <0=> 外部时钟 <1=> 内核时钟
// <i> 在此配置系统滴答时钟源，您无需再额外配置。
// <i> 如果您使用了外部晶振且系统时钟为8的整数倍，可配置系统滴答时钟源为外部时钟，以提高系统滴答的精度。
#define MCUCFG_SYSTICKCLKSOURCE         1
///////////////////////////////////////////////////////////////////////////////
// <o> 系统启动任务的任务栈大小（Bytes）
// <i> 最小值：
// <i> 未启用浮点寄存器：56B；启用浮点寄存器：192B。
#define MCUCFG_STACKSIZE_STARTER        1024
#if MCUCFG_STACKSIZE_STARTER < MCUCFG_BASICSTACKSIZE
#error 非法的设置值！
#endif

// <o> 系统空闲任务的任务栈大小（Bytes）
// <i> 最小值：
// <i> 未启用浮点寄存器：56B；启用浮点寄存器：192B。
#define MCUCFG_STACKSIZE_SYSIDLE        512
#if MCUCFG_STACKSIZE_SYSIDLE < MCUCFG_BASICSTACKSIZE
#error 非法的设置值！
#endif
///////////////////////////////////////////////////////////////////////////////
// <h> PendSV_Handler设置
// <i> 您即可选择PendSV_Handler，也可选择一个未使用的IRQHandler做为PendSV_Handler，用于执行系统的挂起服务。
// <i> 二者之间的差别在于：
// <i> PendSV_Handler：要求MCU必须有BASEPRI寄存器，同时您不能调用xMaskingPRI和xResumePRI进出全局临界区，也不允许私自使用BASEPRI寄存器。
// <i> XXX_IRQHandler：CosyOS将不会使用PendSV_Handler和BASEPRI寄存器，您可随意处置它们。如果MCU有BASEPRI寄存器，您可调用xMaskingPRI和xResumePRI进出全局临界区。
// <i> 如Cortex-M0/M0+/M23等内核，都没有BASEPRI寄存器，就不能使用PendSV_Handler。
// <i> 再比如您虽使用了Cortex-M3/M4/M33/M7等内核，但确想调用xMaskingPRI和xResumePRI来实现不同掩蔽范围的全局临界区保护，也不能使用PendSV_Handler。

// <o> 挂起服务中断选择
// <0=> PendSV_Handler <1=> XXX_IRQHandler
// <i> 如果您选择了XXX_IRQHandler，还需在下方设置中断服务函数名称和中断向量号，而后您无需再对该中断做更多的设置，CosyOS将自动完成剩余的工作。
#define MCUCFG_PENDSV                   0

#if !MCUCFG_PENDSV
#define PendSV_Replacer                 PendSV_Handler
#else
// <o> 中断服务函数名称
// <i> 此项您应在文本编辑界面中定义。
// <i> 示例：EXTI0_IRQHandler
#define PendSV_Replacer                 EXTI0_IRQHandler

// <o> 中断向量号
// <i> 如果不能直接写出数字，应在文本编辑界面中定义。
// <i> 示例：EXTI0_IRQn
#define MCUCFG_PENDSVIRQ                EXTI0_IRQn

#endif
// </h>
///////////////////////////////////////////////////////////////////////////////
// <o> PendSV_FIFO深度
// <i> 此项参数取决于您在中断中调用挂起服务的总数及中断的频率。
// <i> 对于Cortex-M来说，CosyOS规定PendSV_FIFO的最大深度为255。
// <i> 可开启PendSV_FIFO监控功能，监控历史上的最大值，再适当增大，以确保其不会溢出。
#define MCUCFG_PENDSVFIFO_DEPTH         64
#if MCUCFG_PENDSVFIFO_DEPTH > 255
#error PendSV_FIFO深度值溢出！
#endif
///////////////////////////////////////////////////////////////////////////////

                //*** <<< end of configuration section >>> ***//

/******************************************************************************
 *                        Compiler Related Definitions                        *
 ******************************************************************************/

#include SYSCFG_STANDARDHEAD
#if __FPU_PRESENT == __ENABLED__ && __FPU_USED == __ENABLED__
#define MCUCFG_HARDWAREFPU  __ENABLED__
#else
#define MCUCFG_HARDWAREFPU  __DISABLED__
#endif

/******************************************************************************
 *                               OS Definitions                               *
 ******************************************************************************/

/* Header */
#include <string.h>
#include "..\System\os_base.h"

/* Memory */
#define _SYS_MEM_
#define _CODE_MEM_
#define _CONST_MEM_
#define _STACK_MEM_
#define _MALLOC_MEM_
#define _XDATA_MEM_
#define _OBJ_MEM_

/* Register */
#define _SYS_REG_

/* Typedef */
typedef unsigned long long int s_u64_t;
typedef s_bool_t m_bit_t;
typedef s_u32_t  m_sp_t;
typedef s_u32_t  m_taskmsg_t;
typedef s_u32_t  m_fetion_t;
typedef s_u32_t  m_stacksize_t;
typedef s_u32_t  m_pc_t;
typedef s_u32_t  m_tick_t;
typedef s_u32_t  m_group_t;

/* Extern */
extern s_u32_t  m_basepri;
extern s_u32_t *m_taskmsg_psp;
extern s_u8_t   mPendSV_FIFO_DepthMAX;
extern   void  *mPendSV_FIFO[2][MCUCFG_PENDSVFIFO_DEPTH + 1];
register void **mPendSV_P0 __ASM("r10");
register void **mPendSV_P1 __ASM("r11");
extern void mu_enter_critical(void);
extern void mu_exit_critical(void);
extern void mu_reenter_critical(void);
extern void mu_reexit_critical(void);
extern s_u32_t mx_masking_pri(s_u32_t newpri);
extern void mPendSV_Loader(void *addr);
extern void mPendSV_Handler(void);
extern void mTaskStack_PUSHPOP(s_bool_t, void *);

/* CONST & ATTRIBUTE */
#define MCUCFG_GNU                __ENABLED__
#define MCUCFG_NOP                __NOP()
#define MCUCFG_ISA                __ARM__
#define MCUCFG_PCLEN              4
#define MCUCFG_USING
#define MCUCFG_C51USING
#define MCUCFG_SYSTICK_ATTRIBUTE
#define MCUCFG_PENDSV_ATTRIBUTE
#define MCUCFG_251_REENTRANT
#define MCUCFG_TASKMSG_TYPE       1
#define MCUCFG_TASKMSG_PSP        m_taskmsg_psp = (s_u32_t *)__m_get_psp()
#define MCUCFG_TASKMSG_VAR        m_taskmsg_t r0__, m_taskmsg_t r1__, m_taskmsg_t r2__, m_taskmsg_t r3__
#define MCUCFG_TASKMSG_VAL        0, 0, 0, 0
#define MCUCFG_TASKMSG_SIZE       ((&m0 - &m0_ - 1) * 4)
#if MCUCFG_HARDWAREFPU == __ENABLED__
#define MCUCFG_CALLER_PUSH_FPU    (18 * 4) /* {s0-s15,FPSCR,UNKNOW} */
#define MCUCFG_CALLEE_PUSH_FPU    (16 * 4) /* {s16-s31} */
#else
#define MCUCFG_CALLER_PUSH_FPU    0
#define MCUCFG_CALLEE_PUSH_FPU    0
#endif
#define MCUCFG_CALLER_PUSH_REG    (8 * 4) /* {r0-r3,r12,r14(lr),r15(pc),xPSR} */
#define MCUCFG_CALLEE_PUSH_REG    (6 * 4) /* {r4-r9} */
#define MCUCFG_CALLER_PUSH        (MCUCFG_CALLER_PUSH_FPU + MCUCFG_CALLER_PUSH_REG)
#define MCUCFG_CALLEE_PUSH        (MCUCFG_CALLEE_PUSH_FPU + MCUCFG_CALLEE_PUSH_REG)
#define MCUCFG_BASICSTACKSIZE     (MCUCFG_CALLER_PUSH + MCUCFG_CALLEE_PUSH)
#define MCUCFG_STACK_ALIGN        __align(8)
#if SYSCFG_DEBUGGING == __ENABLED__
#define MCUCFG_TASKSTACK_MONITOR  __ENABLED__
#else
#define MCUCFG_TASKSTACK_MONITOR  __DISABLED__
#endif
#define MCUCFG_STACKSIZE_TASKMGR  (MCUCFG_BASICSTACKSIZE * 2 + (MCUCFG_HARDWAREFPU == __ENABLED__ ? 0 : 24))
#define MCUCFG_STACKSIZE_DEBUGGER (MCUCFG_BASICSTACKSIZE * 2)

/* MCUAPI */
#define mSysTick_CLKMOD           (MCUCFG_SYSTICKCLKSOURCE ? 1 : 8)
#define mSysTick_Cycle            (SYSCFG_SYSCLK / (1000000UL / SYSCFG_SYSTICKCYCLE) / mSysTick_CLKMOD)
#if mSysTick_Cycle > 0x00FFFFFF
#error 系统滴答定时器溢出，必须减小系统时钟或系统滴答周期。
#elif 1000000UL % SYSCFG_SYSTICKCYCLE
#warning 每秒钟的系统滴答周期数不为整数，建议重新调整系统滴答周期。
#elif SYSCFG_SYSCLK % (1000000UL / SYSCFG_SYSTICKCYCLE)
#warning 每秒钟的系统滴答周期数不为整数，建议重新调整系统时钟或系统滴答周期。
#elif SYSCFG_SYSCLK / (1000000UL / SYSCFG_SYSTICKCYCLE) % mSysTick_CLKMOD
#warning 每秒钟的系统滴答周期数不为整数，建议重新调整系统时钟或系统滴答周期。
#endif
#define mSysTick_InitValue        mSysTick_Cycle
#define mSysTick_Counter          SysTick->VAL
#define mSysTick_Disable          SysTick->CTRL = (MCUCFG_SYSTICKCLKSOURCE ? 0x04 : 0x00) | 0x01
#define mSysTick_Enable           SysTick->CTRL = (MCUCFG_SYSTICKCLKSOURCE ? 0x04 : 0x00) | 0x01 | 0x02
#define mTaskNode_Head_           m_sp_t psp;
#define mTaskNode_Tail_           m_sp_t psp_top;

#if !MCUCFG_PENDSV
#define mPendSV_Priority          *(volatile s_u8_t  *)0xE000ED22 = 0xFF
#define mPendSV_Set               *(volatile s_u32_t *)0xE000ED04 = 0x10000000
#define mPendSV_INIT \
do{ \
	mPendSV_Priority; \
	m_basepri <<= 7 - ((*(volatile s_u32_t *)0xE000ED00 >> 8) & 7); \
	m_basepri--; \
	m_basepri <<= 1 + ((*(volatile s_u32_t *)0xE000ED00 >> 8) & 7); \
	__mx_resume_pri(0); \
}while(false)
#define muEnterCritical           mu_enter_critical()
#define muExitCritical            __mx_resume_pri(0)
#else
#define mPendSV_Priority          *(volatile s_u32_t *)(0xE000E400 + MCUCFG_PENDSVIRQ /  4 * 4)|= 0xFF << (MCUCFG_PENDSVIRQ % 4) * 8
#define mPendSV_Disable           *(volatile s_u32_t *)(0xE000E180 + MCUCFG_PENDSVIRQ / 32 * 4) = 0x01 << (MCUCFG_PENDSVIRQ % 32)
#define mPendSV_Enable            *(volatile s_u32_t *)(0xE000E100 + MCUCFG_PENDSVIRQ / 32 * 4) = 0x01 << (MCUCFG_PENDSVIRQ % 32)
#define mPendSV_Set               *(volatile s_u32_t *)(0xE000E200 + MCUCFG_PENDSVIRQ / 32 * 4) = 0x01 << (MCUCFG_PENDSVIRQ % 32)
#define mPendSV_INIT \
do{ \
	mPendSV_Priority; \
	m_basepri = 1 + ((*(volatile s_u32_t *)0xE000ED00 >> 8) & 7); \
	mPendSV_Enable; \
}while(false)
#define muEnterCritical           mu_enter_critical()
#define muExitCritical            mu_exit_critical()
#endif

#define muReEnterCritical         mu_reenter_critical()
#define muReExitCritical          mu_reexit_critical()
#define mxMaskingPRI(newpri)      mx_masking_pri(newpri)
#define mxDisableIRQ              __mx_disable_irq()
#define mxDisableFIQ              __mx_disable_fiq()
#define mxResumeIRQ(oldirq)       __mx_resume_irq(oldirq)
#define mxResumeFIQ(oldfiq)       __mx_resume_fiq(oldfiq)
#define mxResumePRI(oldpri)       __mx_resume_pri(oldpri)

#define mSys_Idle                 __WFI()

#define mSys_INIT \
do{ \
	mPendSV_P0 = mPendSV_FIFO[0]; \
	mPendSV_P1 = mPendSV_FIFO[1]; \
	__m_set_psp(__m_get_msp() - 2 * MCUCFG_BASICSTACKSIZE); \
	__m_set_control(0x02 | (MCUCFG_HARDWAREFPU == __ENABLED__ ? 0x04 : 0x00)); \
	SysTick->LOAD = mSysTick_InitValue; \
	mSysTick_Disable; \
	/* SysTick Priority */ \
	*(volatile s_u8_t  *)0xE000ED23 = 0xFF; \
	/* 栈8字节对齐 */ \
	*(volatile s_u32_t *)0xE000ED14 |= 0x0200; \
	/* CP11|CP10 */ \
	MCUCFG_HARDWAREFPU == __ENABLED__ ? *(volatile s_u32_t *)0xE000ED88 |= (0x0F<<20) : OS_NOPx1; \
	/* ASPEN|LSPEN */ \
	MCUCFG_HARDWAREFPU == __ENABLED__ ? *(volatile s_u32_t *)0xE000EF34 &= 0x3FFFFFFF : OS_NOPx1; \
	mPendSV_INIT; \
	mSysTick_Enable; \
	__asm("cpsie i"); \
}while(false)

#define mTaskmgr_Counting \
	counter2 = (counter1 * 100 * mSysTick_CLKMOD) / (SYSCFG_SYSCLK / 1000000UL) / counter2

#define mSysTick_Counting \
do{ \
	if(tick_temp <= mSysTick_Counter) break; \
	s_tick_counter1 += tick_temp - mSysTick_Counter; \
	s_tick_counter2++; \
}while(false)

#define mTaskStack_INIT \
do{ \
	node_news->psp_top = (m_sp_t)node_news->bsp + node_news->stacksize; \
	if(node_news->psp_top % 8){ \
		node_news->psp_top /= 8; \
		node_news->psp_top *= 8; \
		node_news->stacksize = node_news->psp_top - (m_sp_t)node_news->bsp; \
	} \
	node_news->psp = node_news->psp_top; \
	*(s_u32_t *)(node_news->psp - MCUCFG_CALLER_PUSH_FPU - 4) = 0x01000000; \
	*(s_u32_t *)(node_news->psp - MCUCFG_CALLER_PUSH_FPU - 8) = (s_u32_t)s_task_starter->entry; \
	node_news->psp-= MCUCFG_BASICSTACKSIZE; \
}while(false)

#if MCUCFG_TASKSTACK_MONITOR == __ENABLED__
#define mScheduler_INIT \
	m_stacksize_t stacklen; \
	s_sign_scheduling = false

#define mTaskStack_LEN \
	stacklen = s_task_current->psp_top - __m_get_psp() + MCUCFG_CALLEE_PUSH

#define mEvery_Monitor \
do{ \
	if(s_task_current->stacksize < stacklen){ \
		s_task_current->status = OS_STATUS_STOPPED_TSOF; \
		s_fault.overflow_taskstack = true; \
	} \
}while(false)
#else
#define mScheduler_INIT s_sign_scheduling = false
#define mTaskStack_LEN  do{}while(false)
#define mEvery_Monitor  do{}while(false)
#endif

#if SYSCFG_SAFERUNTIME == __ENABLED__
#define mPUSH_Monitor \
do{ \
	push_f = true; \
	if(s_task_current->pri > node_news->pri){ \
		s_task_current->counter = 0; \
	} \
}while(false)
#else
#define mPUSH_Monitor  push_f = true
#endif

#define mUsedTime_END \
do{ \
	if(usedtime[0]){ \
		usedtime[0]--; \
		usedtime[1] += mSysTick_InitValue - counter; \
	} \
	else{ \
		if(usedtime[1] >= counter){ \
			usedtime[1] -= counter; \
		} \
		else{ \
			usedtime[1] += mSysTick_InitValue - counter; \
		} \
	} \
	s_task_current->usedtime[0] += usedtime[0]; \
	s_task_current->usedtime[0] += (s_task_current->usedtime[1] + usedtime[1]) / mSysTick_Cycle; \
	s_task_current->usedtime[1]  = (s_task_current->usedtime[1] + usedtime[1]) % mSysTick_Cycle; \
}while(false)

#define mUsedTime_INIT \
do{ \
	usedtime[0] = 0; \
	usedtime[1] = counter; \
}while(false)

#define mTaskStack_PUSH do{}while(false)

#define mTaskStack_POP  mTaskStack_PUSHPOP(push_f, node_news)

#define mPendSV_Load \
do{ \
	mPendSV_Loader(&u_psv); \
	mPendSV_Set; \
}while(false)

#define mPendSV_Entry \
	if(mPendSV_P0 > mPendSV_FIFO[0]) mPendSV_Handler()

#define miWriteFlagBits \
	if(!u_psv.value){ \
		do{}while(false)



/*
 * STATIC INLINE
 */

__STATIC_INLINE s_u32_t __m_get_msp(void)
{
	register s_u32_t oldmsp;
	__asm("mrs oldmsp, msp");
	return oldmsp;
}

__STATIC_INLINE s_u32_t __m_get_psp(void)
{
	register s_u32_t oldpsp;
	__asm("mrs oldpsp, psp");
	return oldpsp;
}

__STATIC_INLINE void __m_set_psp(s_u32_t newpsp)
{
	__asm("msr psp, newpsp");
}

__STATIC_INLINE void __m_set_control(s_u32_t newctrl)
{
	__asm("msr control, newctrl");
}

/* 全局临界区 */
__STATIC_INLINE s_u32_t __mx_disable_irq(void)
{
	register s_u32_t oldirq;
	__asm("mrs oldirq, primask");
	__asm("cpsid i");
	return oldirq;
}

__STATIC_INLINE s_u32_t __mx_disable_fiq(void)
{
	register s_u32_t oldfiq;
	__asm("mrs oldfiq, faultmask");
	__asm("cpsid f");
	return oldfiq;
}

__STATIC_INLINE void __mx_resume_irq(s_u32_t oldirq)
{
	__asm("msr primask, oldirq");
}

__STATIC_INLINE void __mx_resume_fiq(s_u32_t oldfiq)
{
	__asm("msr faultmask, oldfiq");
}

__STATIC_INLINE void __mx_resume_pri(s_u32_t oldpri)
{
	__asm("msr basepri, oldpri");
}



#endif
